﻿module WinSocket;

import winapi;

version (Win32){
	pragma(lib,"ws2_32.lib");

	alias UINT_PTR SOCKET;
	alias int     socklen_t;
	alias UINT_PTR socket_t;
	alias uint    GROUP;
	alias ubyte   u_char;
	alias ushort  u_short;
	alias uint    u_int;
	alias uint    u_long;
	alias ubyte  TCHAR;

	const int IOCPARM_MASK =  0x7f;
	const int IOC_IN =        cast(int)0x80000000;
	const int FIONBIO =       cast(int) (IOC_IN | ((int.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126);

	const int WSADESCRIPTION_LEN = 256;
	const int WSASYS_STATUS_LEN = 128;
	const int WSAEWOULDBLOCK =  10035;
	const int WSAEINTR =        10004;
	const int WSA_IO_PENDING=997L;
	const int MSG_PARTIAL=0x8000;

	struct GUID {          // size is 16
		 align(1):
		DWORD Data1;
		WORD  Data2;
		WORD  Data3;
		BYTE  Data4[8];
	}
	
	enum SocketOption:int{
		//consistent
		SO_DEBUG =         0x1,

		//possibly Winsock-only values
		SO_BROADCAST =  0x20,
		SO_REUSEADDR =  0x4,
		SO_LINGER =     0x80,
		SO_DONTLINGER = ~(SO_LINGER),
		SO_OOBINLINE =  0x100,
		SO_SNDBUF =     0x1001,
		SO_RCVBUF =     0x1002,
		SO_ERROR =      0x1007,

		SO_ACCEPTCONN =    0x2, // ?
		SO_KEEPALIVE =     0x8, // ?
		SO_DONTROUTE =     0x10, // ?
		SO_TYPE =          0x1008, // ?

		// OptionLevel.IP settings
		IP_MULTICAST_TTL = 10,
		IP_MULTICAST_LOOP = 11,
		IP_ADD_MEMBERSHIP = 12,
		IP_DROP_MEMBERSHIP = 13,

		// OptionLevel.TCP settings
		TCP_NODELAY = 0x0001,
	}

	enum SocketOptionLevel{
		SOCKET =  0xFFFF,
		IP =      0,
		TCP =     6,
		UDP =     17,
	}

	enum AddressFamily:int{
		UNSPEC =     0,
		UNIX =       1,
		INET =       2,
		IPX =        6,
		APPLETALK =  16,
		//INET6 =      ? // Need Windows XP ?
	}

	union in_addr{
		private union _S_un_t{
			private struct _S_un_b_t{
				ubyte s_b1, s_b2, s_b3, s_b4;
			}
			_S_un_b_t S_un_b;
			
			private struct _S_un_w_t{
				ushort s_w1, s_w2;
			}
			_S_un_w_t S_un_w;
			
			uint S_addr;
		}
		_S_un_t S_un;
		
		uint s_addr;
		
		struct{
			ubyte s_net, s_host;
			union{
				ushort s_imp;
				struct{
					ubyte s_lh, s_impno;
				}
			}
		}
	}

	struct sockaddr{
		short sa_family;
		ubyte[14] sa_data;
	}

	struct sockaddr_in {
		short    sin_family;
		u_short  sin_port;
		in_addr  sin_addr;
		ubyte[8] sin_zero;
	};
		
	struct WSADATA{
		WORD wVersion;
		WORD wHighVersion;
		char szDescription[WSADESCRIPTION_LEN+1];
		char szSystemStatus[WSASYS_STATUS_LEN+1];
		ushort iMaxSockets;
		ushort iMaxUdpDg;
		char* lpVendorInfo;
	}
	alias WSADATA* LPWSADATA;

	struct WSAOVERLAPPED{
		DWORD    Internal;
		DWORD    InternalHigh;
		DWORD    Offset;
		DWORD    OffsetHigh;
		HANDLE   hEvent;
	};
	alias WSAOVERLAPPED* LPWSAOVERLAPPED;

	struct WSABUF{
		u_long  len;     /* the length of the buffer */
		char*   buf;     /* the pointer to the buffer */
	};
	alias WSABUF* LPWSABUF;

	const int MAX_PROTOCOL_CHAIN =7;
	struct WSAPROTOCOLCHAIN{
		int ChainLen;
		DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
	};
	alias WSAPROTOCOLCHAIN* LPWSAPROTOCOLCHAIN;

	const int WSAPROTOCOL_LEN=255;
	struct WSAPROTOCOL_INFO{
		DWORD dwServiceFlags1;
		DWORD dwServiceFlags2;
		DWORD dwServiceFlags3;
		DWORD dwServiceFlags4;
		DWORD dwProviderFlags;
		GUID ProviderId;
		DWORD dwCatalogEntryId;
		WSAPROTOCOLCHAIN ProtocolChain;
		int iVersion;
		int iAddressFamily;
		int iMaxSockAddr;
		int iMinSockAddr;
		int iSocketType;
		int iProtocol;
		int iProtocolMaxOffset;
		int iNetworkByteOrder;
		int iSecurityScheme;
		DWORD dwMessageSize;
		DWORD dwProviderReserved;
		TCHAR szProtocol[WSAPROTOCOL_LEN+1];
	};
	alias WSAPROTOCOL_INFO* LPWSAPROTOCOL_INFO;
	struct OVERLAPPED
	{
		DWORD Internal;
		DWORD InternalHigh;
		DWORD Offset;
		DWORD OffsetHigh;
		HANDLE hEvent;
	}

	alias OVERLAPPED* LPOVERLAPPED;

	struct SYSTEM_INFO_U
	{

		union
		{
			struct
			{
				DWORD dwOemId;
			}
			struct
			{
				ushort wProcessorArchitecture;
				ushort wReserved;
			}
		}
	}


	struct SYSTEM_INFO
	{
		SYSTEM_INFO_U u;
		DWORD dwPageSize;
		LPVOID lpMinimumApplicationAddress;
		LPVOID lpMaximumApplicationAddress;
		DWORD dwActiveProcessorMask;
		DWORD dwNumberOfProcessors;
		DWORD dwProcessorType;
		DWORD dwAllocationGranularity;
		ushort wProcessorLevel;
		ushort wProcessorRevision;
	}
	alias SYSTEM_INFO* LPSYSTEM_INFO;
	alias SYSTEM_INFO _SYSTEM_INFO;
	alias SYSTEM_INFO TSYSTEMINFO;
	alias SYSTEM_INFO* PSYSTEMINFO;
	
	extern(Windows){
		int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
		int WSACleanup();
		socket_t socket(int af, int type, int protocol);
		int ioctlsocket(socket_t s, int cmd, uint* argp);
		uint inet_addr(char* cp);
		int bind(socket_t s, sockaddr* name, int namelen);
		int connect(socket_t s, sockaddr* name, int namelen);
		int listen(socket_t s, int backlog);
		socket_t accept(socket_t s, sockaddr* addr, int* addrlen);
		int closesocket(socket_t s);
		int shutdown(socket_t s, int how);
		int getpeername(socket_t s, sockaddr* name, int* namelen);
		int getsockname(socket_t s, sockaddr* name, int* namelen);
		int send(socket_t s, void* buf, int len, int flags);
		int sendto(socket_t s, void* buf, int len, int flags, sockaddr* to, int tolen);
		int recv(socket_t s, void* buf, int len, int flags);
		int recvfrom(socket_t s, void* buf, int len, int flags, sockaddr* from, int* fromlen);
		//int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* errorfds, timeval* timeout);
		int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
		int setsockopt(socket_t s, int level, int optname, void* optval, int optlen);
		int gethostname(void* namebuffer, int buflen);
		char* inet_ntoa(uint ina);
		//hostent* gethostbyname(char* name);
		//hostent* gethostbyaddr(void* addr, int len, int type);
		int WSAGetLastError();
		SOCKET WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFO lpProtocolInfo,GROUP g,DWORD dwFlags);
		HANDLE CreateIoCompletionPort(HANDLE, HANDLE, ULONG_PTR, DWORD);
		int WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,void* lpCompletionRoutine);
		BOOL GetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytes,ULONG_PTR *lpCompletionKey,LPOVERLAPPED* lpOverlapped,DWORD dwMilliseconds);
		BOOL WSAGetOverlappedResult(SOCKET s,WSAOVERLAPPED *lpOverlapped,DWORD *lpcbTransfer,BOOL fWait,DWORD *lpdwFlags);
		int WSARecvFrom(SOCKET s,WSABUF *lpBuffers,DWORD dwBufferCount,DWORD *lpNumberOfBytesRecvd,DWORD *lpFlags,sockaddr *lpFrom,int *lpFromlen,WSAOVERLAPPED *lpOverlapped,void* lpCompletionRoutine);
		BOOL PostQueuedCompletionStatus(HANDLE CompletionPort,DWORD dwNumberOfBytesTransferred,ULONG_PTR dwCompletionKey,OVERLAPPED *lpOverlapped);
		int WSASend(SOCKET s,WSABUF *lpBuffers,DWORD dwBufferCount,DWORD *lpNumberOfBytesSent,DWORD dwFlags,WSAOVERLAPPED *lpOverlapped,void* lpCompletionRoutine);
		int WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,DWORD *lpNumberOfBytesSent,DWORD dwFlags,sockaddr *lpTo,int iTolen,WSAOVERLAPPED *lpOverlapped,void* lpCompletionRoutine);

		void GetSystemInfo(LPSYSTEM_INFO);
	}
}

enum SocketType:int{
	STREAM =     1,       /// sequenced, reliable, two-way communication-based byte streams
	DGRAM =      2,        /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
	RAW =        3,          /// raw protocol access
	RDM =        4,          /// reliably-delivered message datagrams
	SEQPACKET =  5,    /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
}

enum ProtocolType:int{
	IP =    0,     /// internet protocol version 4
	ICMP =  1,   /// internet control message protocol
	IGMP =  2,   /// internet group management protocol
	GGP =   3,    /// gateway to gateway protocol
	TCP =   6,    /// transmission control protocol
	PUP =   12,    /// PARC universal packet protocol
	UDP =   17,    /// user datagram protocol
	IDP =   22,    /// Xerox NS protocol
}

enum ExWSASocket:int{
	OVERLAPPED        =0x01,
	MULTIPOINT_C_ROOT =0x02,
	MULTIPOINT_C_LEAF =0x04,
	MULTIPOINT_D_ROOT =0x08,
	MULTIPOINT_D_LEAF =0x10,
}

enum SocketEr{
	INVALID_SOCKET=(~0),
	SOCKET_ERROR  =(-1),
}